package life;

import java.util.ArrayList;

public class World
{
	int age;
	Coordinate extension;
	private ArrayList<Food> foodMap = new ArrayList<Food>();
	private ArrayList<Liso> lisoMap = new ArrayList<Liso>();
	int lisoLifeSpan;
	private int surface;
	int born;
	int die;
	double prob;
	double mutationProbability;

	public World(Coordinate extension)
	{
		this.extension = extension;
		surface = (int) (extension.x * extension.y);
		mutationProbability=0.08;
	}

	public void age()
	{
		age++;
		ageFood();
		ageLiso();

	}

	/**
	 * Age Liso and rid world of dead Liso
	 */
	private void ageLiso()
	{
		ArrayList<Liso> actualLiso = new ArrayList<Liso>();
		for (Liso l : lisoMap)
		{
			l.aged();
			if (l.isStillAlive())
				actualLiso.add(l);
		}
		die = lisoMap.size() - actualLiso.size();
		lisoMap = actualLiso;
	}

	/**
	 * Age Food and rid World from dead Food
	 */
	private void ageFood()
	{
		ArrayList<Food> actualFood = new ArrayList<Food>();
		for (Food f : foodMap)
		{
			f.aged();
			if (f.isStillAlive())
				actualFood.add(f);
		}
		foodMap = actualFood;
	}

	public void createFood(int foodAmmonut, int foodLifeSpan)
	{
		for (int i = 0; i < foodAmmonut; i++)
		{
			foodMap.add(new Food(this, foodLifeSpan));
		}

	}

	public void createLiso(int lisoAmmonut, int lisoLifeSpan)
	{
		this.lisoLifeSpan = lisoLifeSpan;
		for (int i = 0; i < lisoAmmonut; i++)
		{
			lisoMap.add(new Liso(this, lisoLifeSpan,1));
		}

	}

	public void moveLiso()
	{
		for (Liso l : lisoMap)
		{
			l.move(this);
		}
	}

	public void spawnFood(double foodSpawnProbablility, int foodLifeSpan)
	{
		for (int i = 0; i < this.surface / 10000; i++)
		{
			if (Math.random() < foodSpawnProbablility)
			{
				Food f = new Food(this, foodLifeSpan);
				foodMap.add(f);
				// System.out.println("\t\t new Food");
			}
		}

	}

	public void lisoEat()
	{
		ArrayList<Food> actualFood = new ArrayList<Food>();
		Food foodNotEat = null;
		for (Food f : foodMap)
		{
			foodNotEat = f;
			for (Liso l : lisoMap)
			{
				if (l.willEat(f))
				{
					l.eat(f);
					foodNotEat = null;
				}
			}

			if (foodNotEat != null)
				actualFood.add(foodNotEat);
		}
		if (foodMap.size() - actualFood.size() > 0)
			// System.out.println("\t\t" + (foodMap.size() - actualFood.size())
			// + " Eaten Food");
			foodMap = actualFood;
	}

	public boolean asLisoAlive()
	{
		return lisoMap.size() > 0;
	}

	public void spawnLiso()
	{
		// if(sovrapopulate())
		// return;
		prob = 40.0 / lisoMap.size();
		if (prob < 0.02)
		{
			System.out.println("Sovrapopolate");
			prob = 0;
			born=0;
			return;
		}
		if (prob > 1)
		{
			prob = 1;
		}
		ArrayList<Liso> babyes = new ArrayList<Liso>();
		for (Liso l1 : lisoMap)
		{
			for (Liso l2 : lisoMap)
			{

				if (l1.equals(l2))
					continue;

				if (l1.conception(l2, prob))
					babyes.add(l1.createNewLiso(this,l2));
			}
		}
		born = babyes.size();
		lisoMap.addAll(babyes);
	}

	private boolean sovrapopulate()
	{
		if (lisoMap.size() > surface / 100)
		{
			System.out.println("Sovrapopulated Wrold! " + "liso > " + surface / 100);
			return true;
		}
		return false;
	}

	public ArrayList<Food> getFoodMap()
	{
		return foodMap;
	}

	public void setFoodMap(ArrayList<Food> foodMap)
	{
		this.foodMap = foodMap;
	}

	public ArrayList<Liso> getLisoMap()
	{
		return lisoMap;
	}

	public void setLisoMap(ArrayList<Liso> lisoMap)
	{
		this.lisoMap = lisoMap;
	}

	public int getBorn()
	{
		return born;
	}

	public void setBorn(int born)
	{
		this.born = born;
	}

	public int getDie()
	{
		return die;
	}

	public void setDie(int die)
	{
		this.die = die;
	}

	public double getProb()
	{
		return prob;
	}

	public void foodAwarness()
	{
		ArrayList<Food> foodaWare ;
		for (Liso l : lisoMap)
		{
			foodaWare = new ArrayList<Food>();
			for (Food f : foodMap)
			{
				if (l.isAware(f))
					foodaWare.add(f);		//collect all food noticed by Liso		
			}
			
			if(foodaWare.size()>0)
				l.moveTowardFood(foodaWare);//select the correct Food(closest)
		}

	}
	
	public String getLisoStat(){
		String res="";
		if (lisoMap.size()<1)
			return res;
		
		Liso l1 = lisoMap.get(0);
		String[] params= new String[l1.getProp().keySet().size()];
		int n=0;
		for(Object k : l1.getProp().keySet())
		{
			params[n++]=(String)(k);
		}
		
		double[] means = new double[params.length];
		
		n=0;
		for (Liso l : lisoMap)
		{
			int j=0;
			for(Object k : l1.getProp().keySet())
			{
				means[j]=means[j]+Double.parseDouble(l.getProp().getProperty((String)k));
				j++;
			}
			n++;
		}
		
		for(int k=0;k<means.length;k++){
			means[k]=means[k]/n;			
		//	res=res+params[k]+"="+means[k]+" ; ";
			res=res+means[k]+" ; ";
		}
		
		
		return res;
	}

}
